import { Stream } from 'stream';

import { InjectableStrategy } from '../../common/types/injectable-strategy';

// This is a workaround for a type mismatch between express v5 (Vendure core)
// and express v4 (several transitive dependencies). Can be replaced with the
// actual Request type once the ecosystem has more significantly shifted to v5.
type Request = {
    headers: Record<string, string>;
    url: string;
    method: string;
    body: any;
    query: any;
    params: any;
    ip: string;
} & any;

/**
 * @description
 * The AssetPersistenceStrategy determines how Asset files are physically stored
 * and retrieved.
 *
 * :::info
 *
 * This is configured via the `assetOptions.assetStorageStrategy` property of
 * your VendureConfig.
 *
 * :::
 *
 * @docsCategory assets
 */
export interface AssetStorageStrategy extends InjectableStrategy {
    /**
     * @description
     * Writes a buffer to the store and returns a unique identifier for that
     * file such as a file path or a URL.
     */
    writeFileFromBuffer(fileName: string, data: Buffer): Promise<string>;

    /**
     * @description
     * Writes a readable stream to the store and returns a unique identifier for that
     * file such as a file path or a URL.
     */
    writeFileFromStream(fileName: string, data: Stream): Promise<string>;

    /**
     * @description
     * Reads a file based on an identifier which was generated by the writeFile
     * method, and returns the as a Buffer.
     */
    readFileToBuffer(identifier: string): Promise<Buffer>;

    /**
     * @description
     * Reads a file based on an identifier which was generated by the writeFile
     * method, and returns the file as a Stream.
     */
    readFileToStream(identifier: string): Promise<Stream>;

    /**
     * @description
     * Deletes a file from the storage.
     */
    deleteFile(identifier: string): Promise<void>;

    /**
     * @description
     * Check whether a file with the given name already exists. Used to avoid
     * naming conflicts before saving the file.
     */
    fileExists(fileName: string): Promise<boolean>;

    /**
     * @description
     * Convert an identifier as generated by the writeFile... methods into an absolute
     * url (if it is not already in that form). If no conversion step is needed
     * (i.e. the identifier is already an absolute url) then this method
     * should not be implemented.
     */
    toAbsoluteUrl?(request: Request, identifier: string): string;
}
